# *_*coding:utf-8 *_*
import base64
import hashlib
import json
import logging
import os
import platform
import re
import subprocess
import time
import uuid
from pathlib import Path
from random import choice

import requests

DEBUG = False
Proxies = {"http": "http://127.0.0.1:10809", "https": "http://127.0.0.1:10809"}
Proxies = {}
# Proxies = {}
logger = logging.getLogger()

UserAgents = [
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"
]
# find operating system
# os_type >> Linux or Darwin(Mac osx) or Windows(Microsoft Windows) or
# FreeBSD or OpenBSD
os_type = platform.system()

# user home address
home_address = os.path.expanduser("~")


def mkdir(path):
    Path(path).mkdir(parents=True, exist_ok=True)


def get_headers(headers):
    default_headers = {'User-Agent': choice_agents()}
    default_headers.update(headers) if isinstance(headers, dict) else default_headers
    return default_headers


def choice_agents():
    return choice(UserAgents)


def init_proxies(use_proxies):
    return Proxies if use_proxies else None


class NsqWriter():
    def __init__(self, nsqd_http_hosts, topic=None):
        self.nsqd_http_hosts = nsqd_http_hosts
        self.topic = topic

    def produce(self, msg=None, topic=None):
        if not msg:
            print("Error, call produce, msg:", msg)
            return

        topic = topic or self.topic
        if topic is None:
            print("Error, call produce, topic is None")
            return

        try:
            host = choice(self.nsqd_http_hosts)
            url = "http://" + str(host) + "/pub?topic=" + topic
            print(url)
            r = requests.post(url, data=msg)
            print(r.text, topic)
        except Exception as e:
            print("Exception: ", e)


# this function converts file_size to KiB or MiB or GiB
def humanReadbleSize(size):
    labels = ['KiB', 'MiB', 'GiB', 'TiB']
    i = -1
    if size < 1024:
        return str(size) + ' B'

    while size >= 1024 and i < 3:
        i += 1
        size = size / 1024

    p = 2 if i > 1 else None
    return str(round(size, p)) + ' ' + labels[i]


# this function checks free space in hard disk.
def freeSpace(dir):
    try:
        import psutil
    except Exception as e:
        print("Error: ", e)
        return None

    try:
        dir_space = psutil.disk_usage(dir)
        free_space = dir_space.free
        return int(free_space)
    except Exception as e:
        print("Error: ", e)
        return None


def getDownloadPath():
    print("Os Type : ", os_type)
    if os_type == "Linux":
        return os.path.join(str(home_address), "downloads")
    elif os_type == "Windows":
        # return os.path.join(str(home_address), "downloads")
        return os.path.join(str(r"C:\video"), "download")
    else:
        return "download/"


def setpos(PosFile, savedpicname, old_savedpicname):
    new_data = "  ".join([savedpicname, old_savedpicname])
    with open(PosFile, "w", encoding="utf-8") as f:
        f.write(new_data)


# 获取上次保存于文件中的下载位置
def getpos(PosFile):
    if not Path(PosFile).exists():
        # 没有保存上次的位置，使用默认值
        return ""
    with open(PosFile, 'r', encoding="utf-8") as f:
        data = f.read().split("  ")
        if len(data) == 2:
            savedpicname, _ = data
        else:
            savedpicname = ""
    return savedpicname


def try_catch(func):
    def inner(self, *args, **kwargs):
        ret = None
        erro = False
        try:
            ret = func(self, *args, **kwargs)
        except Exception as e:
            erro = True
            print("Run Error : {}!!".format(e))
        if not erro and self.new_stop_name is not None:
            setpos(self.PosFileName, self.new_stop_name, self.stop_name)

        return ret

    return inner


def validateTitle(title):
    """
    校验文件名称是否合法, 主要针对windows
    :param title: strng 名称
    :return: string 替换后的名称
    """
    rstr = r"[\/\\\:\*\?\"\<\>\|]"  # '/ \ : * ? " < > |'
    new_title = re.sub(rstr, "", title)  # 替换为下划线
    return new_title.strip()


def int_or_zero(num):
    try:
        out = int(num)
    except Exception as e:
        print("[ int_or_zero Error() ]: ", e)
        return 0
    return out


# hashlib简单使用
def md5(arg):  # 这是加密函数，将传进来的函数加密
    md5_pwd = hashlib.md5(bytes('abd', encoding='utf-8'))
    md5_pwd.update(bytes(arg, encoding='utf-8'))
    return md5_pwd.hexdigest()  # 返回加密的数据


def img_url2image_type(img_url):
    img_url = img_url.rsplit("/")
    if not len(img_url):
        raise Exception("Not a imgae!")
    img_url = img_url[-1]
    img_type = re.search(r"bmp|jpg|png|tif|gif|pcx|tga|exif|fpx|svg|psd|cdr|pcd|dxf|ufo|eps|ai|raw|WMF|webp",
                         img_url)
    if img_type:
        return img_type.group()
    else:
        print("Use Default Img Type")
        return "jpg"


def func_tool(func):
    def inner(*args, **kwargs):
        func_name = func.__name__
        start = time.time()
        print(">> Enter FuncName: {} Args: {} Kwargs:{}".format(func_name, args, kwargs))
        out = func(*args, **kwargs)
        print("<< Out FuncName: {} Cost: {}".format(func_name, time.time() - start))
        return out

    return inner


def func_tool_factory(message_handle=None):
    if hasattr(message_handle, "info"):
        msg_handle = message_handle.info
    else:
        msg_handle = print

    def decorator(func):
        def inner(*args, **kwargs):
            func_name = func.__name__
            input_info = ">>FuncName: {} Args: {} Kwargs:{}".format(func_name, args, kwargs)
            msg_handle(input_info)

            out = func(*args, **kwargs)

            out_info = "<<FuncName: {} Out: {}".format(func_name, out)
            msg_handle(out_info)
            return out

        return inner

    return decorator


def _base64_decode(data):
    """bash64解码，要注意原字符串长度报错问题"""
    missing_padding = 4 - len(data) % 4
    if missing_padding:
        data += '=' * missing_padding
    return base64.b64decode(data)


def uuid1():
    out = uuid.uuid1().hex
    return out


def md5_file_obj(f, block_size=2 ** 20):
    md5 = hashlib.md5()
    while True:
        data = f.read(block_size)
        if not data:
            break
        md5.update(data)
    return md5.digest()


def md5_file(rootdir, filename, blocksize=2 ** 20):
    """生成文件的md5值"""
    with open(os.path.join(rootdir, filename), "rb") as f:
        return md5_file_obj(f, block_size=blocksize)


def pprint(data, indent=None, **kwargs):
    """美化json打印"""
    out = json.dumps(data, ensure_ascii=False, indent=indent, **kwargs)
    print(out)


def order_sort(array):
    """对列表去重，返回去重后的列表"""
    order_array = list(set(array))
    order_array.sort(key=array.index)
    return order_array


def order_sort_notinb(array, b):
    """对列表去重，返回去重后的列表"""
    order_array = list(set([i for i in array if i not in b]))
    # tmp = list(filter(lambda x: x in b, array))
    # print(list(set(filter(lambda x: x in b, array))))
    order_array.sort(key=array.index)
    return order_array


def dedupe(items, key=None):
    """
    重复数据删除
    :param items: 列表
    :param key: 指定一个函数用来将序列中的元素转化为可hash类型，
                用来检测重复
    :return: 迭代器
    """
    seen = set()
    for item in items:
        val = item if key is None else key(item)
        if val not in seen:
            yield item
            seen.add(item)


def catch(raise_error=True, default=None, counter=3, ignore_exceptions=None):
    def decorator(func):
        def inner(*args, **kwargs):
            cnt = 0
            while True:
                cnt += 1
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    logger.debug(f"catch exception: {e}")
                    if cnt > counter:
                        if raise_error:
                            if ignore_exceptions or (ignore_exceptions and e not in ignore_exceptions):
                                raise Exception(e)
                        else:
                            return default
                    time.sleep(0.1)

        return inner

    return decorator


def run_command(operation, shell=False, timeout=60):
    process = subprocess.Popen(operation, shell=shell, stdout=subprocess.PIPE)
    process.wait()
    out, err = process.communicate(timeout=timeout)
    rc = process.returncode
    return out, err, rc


def humanReadSecond(secode: int, ndigits=None):
    t = ["秒", "分钟", "小时"]
    u = 0
    o = secode
    base = 60
    while o > base and u < len(t) - 1:
        o = secode / base
        u += 1
    return f"{round(o, ndigits=ndigits)} {t[u]}"


if __name__ == '__main__':
    # mkdir("download/hell")
    pass
    # ret = getDownloadPath()
    # print(ret)
    # ret = freeSpace("./")
    # print("freeSpace: ", ret)
    # ret = humanReadbleSize(ret)
    # print("humanReadbleSize: ", ret)
    # ret = validateTitle("黑色卷发会很土吗?(图片)")
    # print(ret)
    #
    # array = []
    # print(order_sort(array))
    o = md5("1602558000")
    print(o)
